package thread;

class MyBlockingQueue {
    private String[] elems = null;
    private int head = 0;
    private int tail = 0;
    private int size = 0;

    //准备锁对象,使用this也可以
    private Object locker = new Object();

    public MyBlockingQueue(int capacity) {
        elems = new String[capacity];
    }

    public void put(String elem) throws InterruptedException {
        // 锁加到这里和加到方法上本质是一样的, 加到方法上是给 this 加锁, 此处时给locker加锁
         synchronized (locker) {
             while (size >= elems.length) {
                 //队列满了,让这个代码阻塞
                 locker.wait();
                 return;
             }
             //新增的元素要放在 tail 指向的位置
             elems[tail] = elem;
             tail++;
             if(tail >= elems.length) {
                 tail = 0;
             }
             size++;

             // 入队列成功后唤醒
             locker.notify();
         }
    }

    public String take() throws InterruptedException {
        String elem = null;
        synchronized (locker) {
            while (size == 0) {
                //队列空了
                //后续需要这个代码阻塞
                locker.wait();
            }
            //去除head位置的元素并返回
            elem = elems[head];
            head++;
            if (head >= elems.length) {
                head = 0;
            }
            size--;
            locker.notify();
        }
        return elem;
    }
}

public class ThreadDemo29 {
    public static void main(String[] args) throws InterruptedException {
        MyBlockingQueue myBlockingQueue = new MyBlockingQueue(3);
//        myBlockingQueue.put("aaa");
//        myBlockingQueue.put("bbb");
//        myBlockingQueue.put("ccc");
//        myBlockingQueue.put("ddd");
//
//        String elem = "";
//        elem = myBlockingQueue.take();
//        System.out.println("elem:" + elem);
//        elem = myBlockingQueue.take();
//        System.out.println("elem:" + elem);
//        elem = myBlockingQueue.take();
//        System.out.println("elem:" + elem);
//        elem = myBlockingQueue.take();
//        System.out.println("elem:" + elem);

        //生产者
        Thread t1 = new Thread(()->{
            int n = 10;
            while(true) {
                try {
                    myBlockingQueue.put(n+"");
                    System.out.println("生产元素: " + n);
                    n++;

                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        //消费者
        Thread t2 = new Thread(()->{
            while(true) {
                try {
                    String n = myBlockingQueue.take();
                    System.out.println("消费元素: " + n);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.start();
        t2.start();
    }
}
